// Dynamic Load & Store, a.k.a Out-of-Order-Execution, not yet used
// in our current version.


// package nsalt.func


// import chisel3._
// import chisel3.util._

// import nsalt._
// import nsalt.util._


// object MEMOpID {
//   def idle   = "b0000_000".U
//   def load   = "b0001_001".U
//   def store  = "b0001_010".U
//   def storec = "b0010_010".U //store commit
//   def amo    = "b0001_111".U
//   def lr     = "b0001_101".U
//   def sc     = "b0001_110".U
//   def tlb    = "b0100_001".U
//   def vload  = "b1000_001".U
//   def vstore = "b1000_010".U

//   def needLoad(memop: UInt) = memop(0)
//   def needStore(memop: UInt) = memop(1)
//   def needAlu(memop: UInt) = memop(2)
//   def commitToCDB(memop: UInt) = memop(3)
//   def commitToSTQ(memop: UInt) = memop(4)
//   def commitToTLB(memop: UInt) = memop(5)
//   def commitToVPU(memop: UInt) = memop(6)
// }


// trait DynaLoadStoreConst {
//   val INDEP_ADDR_CALC = false
//   val MEM_ORDERING_QUEUE_SIZE = 8
//   val STORE_QUEUE_SIZE = 8
// }

// class DynaLoadStorePort extends FuncUnitPort with Config {

//   val dataW = Input(UInt(XLEN.W))

//   // val instr = Input(UInt(32.W)) // Atom insts need aq rl funct3 bit from instr // TODO
//   val dmem = new SimpleBusUC(addrBits = VIRT_MEM_ADDR_LEN, userBits = DCacheUserBundleWidth)
//   val dtlb = new SimpleBusUC(addrBits = VIRT_MEM_ADDR_LEN, userBits = DCacheUserBundleWidth)

//   val mispredictRec = Flipped(new MisPredictionRecIO)
//   val stMaskIn = Input(UInt(robSize.W))
//   val robAllocate = Input(Valid(UInt(log2Up(robSize).W)))
//   val uopIn = Input(new RenamedDecodeIO)
//   val uopOut = Output(new RenamedDecodeIO)
//   val isMMIO = Output(Bool())
//   val exceptionVec = Output(Vec(16, Bool()))
//   val scommit = Input(Bool())
//   val commitStoreToCDB = Output(Bool())
//   val haveUnfinishedStore = Output(Bool())
//   val flush = Input(Bool())
// }


// class StoreQueueEntry extends NutCoreBundle{
//   val pc       = UInt(VAddrBits.W)
//   val prfidx   = UInt(prfAddrWidth.W) // for debug
//   val brMask   = UInt(checkpointSize.W)
//   val wmask    = UInt((XLEN/8).W) // for store queue forwarding
//   val vaddr    = UInt(VAddrBits.W)
//   val paddr    = UInt(PAddrBits.W)
//   val func     = UInt(7.W)
//   val size     = UInt(2.W)
//   val op       = UInt(7.W)
//   val data     = UInt(XLEN.W)
//   val isMMIO   = Bool()
//   val valid    = Bool()
// }

// class MemOrderQueueEntry extends NutCoreBundle{
//   val pc       = UInt(VAddrBits.W)
//   val isRVC    = Bool()
//   val prfidx   = UInt(prfAddrWidth.W)
//   val brMask   = UInt(checkpointSize.W)
//   val stMask   = UInt(robSize.W)
//   val vaddr    = UInt(VAddrBits.W) // for debug
//   val paddr    = UInt(PAddrBits.W)
//   val func     = UInt(7.W)
//   val size     = UInt(2.W)
//   val op       = UInt(7.W)
//   val data     = UInt(XLEN.W)
//   val fdata    = UInt(XLEN.W) // forwarding data
//   val fmask    = UInt((XLEN/8).W) // forwarding mask
//   val asrc     = UInt(XLEN.W) // alusrc2 for atom inst
//   val rfWen    = Bool()
//   val isMMIO   = Bool()
//   val valid    = Bool()
//   val tlbfin   = Bool()
//   val finished = Bool()
//   val rollback = Bool()
//   val loadPageFault  = Bool()
//   val storePageFault  = Bool()
//   val loadAddrMisaligned  = Bool()
//   val storeAddrMisaligned = Bool()
// }

// class DCacheUserBundle extends NutCoreBundle {
//   val moqidx   = UInt(5.W) //TODO
//   val op       = UInt(7.W)
// }

// class MemReq extends NutCoreBundle {
//   val addr = UInt(VAddrBits.W)
//   val size = UInt(2.W)
//   val wdata = UInt(XLEN.W)
//   val wmask = UInt(8.W)
//   val cmd = UInt(4.W)
//   val user = new DCacheUserBundle
//   val valid = Bool()
// }

// class AtomALU extends NutCoreModule {
//   val io = IO(new NutCoreBundle{
//     val src1 = Input(UInt(XLEN.W))
//     val src2 = Input(UInt(XLEN.W))
//     val func = Input(UInt(7.W))
//     val isWordOp = Input(Bool())
//     val result = Output(UInt(XLEN.W))
//   })

//   // src1: load result
//   // src2: reg  result
//   val src1 = io.src1
//   val src2 = io.src2
//   val func = io.func
//   val isAdderSub = !LSUOpType.isAdd(func) 
//   val adderRes = (src1 +& (src2 ^ Fill(XLEN, isAdderSub))) + isAdderSub
//   val xorRes = src1 ^ src2
//   val sltu = !adderRes(XLEN)
//   val slt = xorRes(XLEN-1) ^ sltu

//   val res = LookupTreeDefault(func(5, 0), adderRes, List(
//     LSUOpType.amoswap -> src2,
//     // LSUOpType.amoadd  -> adderRes,
//     LSUOpType.amoxor  -> xorRes,
//     LSUOpType.amoand  -> (src1 & src2),
//     LSUOpType.amoor   -> (src1 | src2),
//     LSUOpType.amomin  -> Mux(slt(0), src1, src2),
//     LSUOpType.amomax  -> Mux(slt(0), src2, src1),
//     LSUOpType.amominu -> Mux(sltu(0), src1, src2),
//     LSUOpType.amomaxu -> Mux(sltu(0), src2, src1)
//   ))

//   io.result :=  Mux(io.isWordOp, SignExt(res(31,0), 64), res(XLEN-1,0))
// }


